from fastapi import HTTPException, Request, status
from fastapi.responses import StreamingResponse
import sys

from motor.coordinator.models.request import RequestInfo, ReqState
from motor.coordinator.core.instance_manager import InstanceManager
from motor.coordinator.core.request_manager import RequestManager
from motor.config.coordinator import DeployMode, CoordinatorConfig
from motor.coordinator.router.base_router import BaseRouter
from motor.coordinator.router.pd_hybrid_router import PDHybridRouter
from motor.coordinator.router.separate_pd_router import SeparatePDRouter

router_map: dict[DeployMode, type['BaseRouter']] = {
    DeployMode.PD_SEPARATE: SeparatePDRouter,
    DeployMode.SINGLE_NODE: PDHybridRouter,
}

async def handle_request(raw_request: Request) -> StreamingResponse:
    """Handle incoming requests and route them to appropriate router implementation
    
    Args:
        raw_request: The incoming FastAPI request object
        
    Returns:
        StreamingResponse: The response stream from the selected router implementation
        
    Raises:
        HTTPException: If request body is empty or request fail
    """
    request_body = await raw_request.body()
    if not request_body:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Empty request body")

    # Add request
    req_len = len(request_body)
    req_id = RequestManager().generate_request_id()
    request_json = await raw_request.json()
    req_info = RequestInfo(req_id=req_id, req_data=request_json.copy(), api="v1/chat/completions", 
                           req_len=req_len, state=ReqState.ARRIVE)

    # Check instances
    if not InstanceManager().is_available():
        req_info.update_state(ReqState.EXCEPTION)
        raise HTTPException(status_code=503, detail="No available instances")

    deploy_mode_str = CoordinatorConfig().scheduler_config.get("deploy_mode")
    deploy_mode = DeployMode.from_string(deploy_mode_str)
    router_impl_class = router_map.get(deploy_mode)
    if not router_impl_class:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Unknown deploy mode: {deploy_mode_str}")
        
    router_impl = router_impl_class(req_info)
    
    try:
        return await router_impl.handle_request()
    except Exception as e:
        import traceback
        exc_info = sys.exc_info()
        print("Error occurred in proxy server"
              f" - {req_info.api} endpoint")
        print(e)
        print("".join(traceback.format_exception(*exc_info)))
        raise